// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Copyright (c) 2010 by Lattice Semiconductor Corporation
// --------------------------------------------------------------------
//
// Permission:
//
//   Lattice Semiconductor grants permission to use this code for use
//   in synthesis for any Lattice programmable logic product.  Other
//   use of this code, including the selling or duplication of any
//   portion is strictly prohibited.
//
// Disclaimer:
//
//   This VHDL or Verilog source code is intended as a design reference
//   which illustrates how these types of functions can be implemented.
//   It is the user's responsibility to verify their design for
//   consistency and functionality through the use of formal
//   verification methods.  Lattice Semiconductor provides no warranty
//   regarding the use or functionality of this code.
//
// --------------------------------------------------------------------
//           
//                     Lattice Semiconductor Corporation
//                     5555 NE Moore Court
//                     Hillsboro, OR 97214
//                     U.S.A
//
//                     TEL: 1-800-Lattice (USA and Canada)
//                          503-268-8001 (other locations)
//
//                     web: http://www.latticesemi.com/
//                     email: techsupport@latticesemi.com
//
// --------------------------------------------------------------------
//
//  Project:           7:1 LVDS Video Interface
//  File:              Loopback_Demo_7_to_1_LVDS_TOP.v
//  Title:             Loopback_Demo_7_to_1_LVDS_TOP
//  Description:       Top level design file of loopback demo reference design
//
// --------------------------------------------------------------------
// Code Revision History :
// --------------------------------------------------------------------
// Ver: | Author   | Mod. Date  | Changes Made:
// V1.0 | shossner | 2010-04-25 | Initial Release
//
// --------------------------------------------------------------------

`timescale 1 ns/ 1 ps

module Loopback_Demo_7_to_1_LVDS_TOP 
     (
     
      // Tx module ports
      TX_eclk,               // 25Mhz (proto board)
      //tx_sclk,
      GSRN,
      TCLK_out,
      TA_out,
      TB_out,
      TC_out,
      TD_out,

      // Rx module ports
      RCLK_in,
      RA_in,
      RB_in,
      RC_in,
      RD_in,
      
      // Status/Debug ports
      SWDIP,
      LED
     );

      
      // Tx module ports
input        TX_eclk  ;    // Tx module input clock
//input        tx_sclk ;
input        GSRN    ;     // Tx module resetn
output       TCLK_out;     // LVDS clock output pair 
output       TA_out  ;     // LVDS data output pair a
output       TB_out  ;     // LVDS data output pair b
output       TC_out  ;     // LVDS data output pair c
output       TD_out  ;     // LVDS data output pair d
                          
      // Rx module ports  
input        RCLK_in;      // LVDS clock input pair 
input        RA_in  ;      // LVDS data input pair a
input        RB_in  ;      // LVDS data input pair b
input        RC_in  ;      // LVDS data input pair c
input        RD_in  ;      // LVDS data input pair d

input  [3:0] SWDIP  ;       // 4-DIP Switch
output [3:0] LED    ;       // 4 LEDs
reg    [3:0] LED    ;       


   
//                      <LVDS cable>
//   ___         ___                     ___ 
//  |   | tx_a  |   |   TA_out/RA_in    |   | rx_a  
//  |Cnt|======>|   |==================>|   |======>
//  |___|       |   |                   |   |       
//   ___        |   |                   |   |       
//  |   | tx_b  |   |   TB_out/RB_in    |   | rx_b  
//  |Cnt|======>|   |==================>|   |======>
//  |___|       | T |                   | R |       
//   ___        | x |                   | x |       
//  |   | tx_c  |   |   TC_out/RC_in    |   | rx_c  
//  |Cnt|======>|   |==================>|   |======>
//  |___|       |   |                   |   |       
//   ___        |   |                   |   |       
//  |   | tx_d  |   |   TD_out/RD_in    |   | rx_d  
//  |Cnt|======>|   |==================>|   |======>
//  |___|       |   |                   |   |
//              |   |                   |   |
//              |   | TCLK_out/RCLK_in  |   |
//              |   |==================>|   |
//              |___|                   |___|

   // 7-bit parallel data ready to be transmited by Tx module
   reg  [6:0] tx_a;
   reg  [6:0] tx_b;
   reg  [6:0] tx_c;
   reg  [6:0] tx_d;

   // 7-bit parallel data received by Rx module
   wire [6:0] rx_a;
   wire [6:0] rx_b;
   wire [6:0] rx_c;
   wire [6:0] rx_d;

   // 7-bit parallel "expected" data created for data comparison
   reg  [6:0] cmp_a;
   reg  [6:0] cmp_b;
   reg  [6:0] cmp_c;
   reg  [6:0] cmp_d;

   // 7-bit error counters showing the data comparison result
   reg  [6:0] err_a;
   reg  [6:0] err_b;
   reg  [6:0] err_c;
   reg  [6:0] err_d;

   reg        sync;                             // input sync words found
   wire       rxpll_lock;                       // lock status from Rx PLL
              
   wire       dphase_lock;                      // lock status from bit_align module
   wire [3:0] dphase;                           // phase alignment from bit_align module
   wire       txpll_lock;                       // placeholder - no Tx PLL in this design
   reg        erra,errb,errc,errd;              // error latches
   wire       berr_a,berr_b,berr_c,berr_d;      // blinking error 
   
   wire       tx_sclk;                          // div-by-3.5 clock for Tx test data generation
   //wire       TX_eclk;
   
   wire       RST;                              // positive assert RST
   reg        stop1, stop2, stop3, stop;        // pipe delay

`ifdef _VCP  // used to detect Aldec Verilog simulation and reduce simulation time
   parameter     BBITS = 8;    // numbers of bits for blinking error counter, simulation
`else
   parameter     BBITS = 23;   // numbers of bits for blinking error counter, 25Mhz clock
`endif

   reg  [BBITS-1:0] blink_count;                // counter for blinking display effect
   reg              blink_time;                 // counter roll-over

   assign RST = ~ GSRN;
   assign txpll_lock = 1'b1;	
   
   //--------------------------------------------------------------------
   //-- Generating four 7-bit data buses as the test patterns
   //--------------------------------------------------------------------
   
   always @(posedge RST or posedge tx_sclk)
   begin
      if (RST) begin
         tx_a <= 7'b0000000;
         tx_b <= 7'b0100000;
         tx_c <= 7'b1000000;
         tx_d <= 7'b1100000;
      end else begin
         tx_a <= tx_a + 1;
         tx_b <= tx_b - 1;
         tx_c <= tx_c + 1;
         tx_d <= tx_d - 1;
      end
   end

   

   //--------------------------------------------------------------------
   //-- sclk generation
   //--------------------------------------------------------------------
    defparam Inst4_CLKDIVC.DIV = "3.5" ;
    defparam Inst4_CLKDIVC.GSR = "ENABLED" ;
    CLKDIVF Inst4_CLKDIVC (.RST(RST), .CLKI(TX_eclk), .ALIGNWD(1'b0), 
        .CDIVX(tx_sclk));
                                        
    //pll_108m_to_378m pll_inst (.CLKI(tx_sclk), .RST(RST), .CLKOP(TX_eclk), .LOCK());


   //--------------------------------------------------------------------
   //-- divider sync signal generation
   //--------------------------------------------------------------------
   always @(posedge TX_eclk or posedge RST)
   begin
      if (RST) begin
         stop1    <= 1'b1;
         stop2    <= 1'b1;
         stop3    <= 1'b1;
         stop     <= 1'b1;
      end else begin
         stop1    <= 1'b0;
         stop2    <= stop1;
         stop3    <= stop2;
         stop     <= stop3;
      end
   end

   //--------------------------------------------------------------------
   //-- Tx module
   //--------------------------------------------------------------------
   
   LVDS_7_to_1_TX tx_inst
                  (
                   .eclk     (TX_eclk),   // Tx module input clock
                   .clk_s    (tx_sclk),   // slow clock for reset circuit
                   .stop     (stop),      // Tx module divider sync signal
                   .RST_Tx   (RST),       // Tx module reset      
                                          
                   .T0_in    (tx_a),      // 7-bit data input 0
                   .T1_in    (tx_b),      // 7-bit data input 1
                   .T2_in    (tx_c),      // 7-bit data input 2
                   .T3_in    (tx_d),      // 7-bit data input 3
                             
                   .TCLK_out (TCLK_out),  // LVDS clock output pair 
                   .T0_out   (TA_out),    // LVDS data output pair 0
                   .T1_out   (TB_out),    // LVDS data output pair 1
                   .T2_out   (TC_out),    // LVDS data output pair 2
                   .T3_out   (TD_out)     // LVDS data output pair 3
                  );
   //--------------------------------------------------------------------
   //-- Rx module
   //--------------------------------------------------------------------

  
   LVDS_7_to_1_RX rx_inst 
                  (
                   .dphase_sel  (SWDIP[3]),
                   .dphase_in   ({1'b0,SWDIP[2:0]}),                  
                   .RCLK_in     (RCLK_in),  // LVDS clock input pair
                   .R0_in       (RA_in),    // LVDS data input pair 0
                   .R1_in       (RB_in),    // LVDS data input pair 1
                   .R2_in       (RC_in),    // LVDS data input pair 2
                   .R3_in       (RD_in),    // LVDS data input pair 3
                                
                   .RCLK_out    (),
                   .R0_out      (rx_a),     // 7-bit data output 0
                   .R1_out      (rx_b),     // 7-bit data output 1
                   .R2_out      (rx_c),     // 7-bit data output 2
                   .R3_out      (rx_d),     // 7-bit data output 3

                   .eclk        (),
                   .stop        (),
                   .sclk        (),
                   .rxpll_lock  (rxpll_lock),              
                   .dphase_lock (dphase_lock),
                   .dphase_out  (dphase)
                  );
  
    
   //--------------------------------------------------------------------
   //-- Comparison Logic
   //--------------------------------------------------------------------

   // Finding the synchronize point for creating comparison data
   always @(posedge RCLK_in)
   begin
      if (!rxpll_lock || !dphase_lock) begin
         sync <= 1'b0;
      end else begin 
         if (rx_a == 7'b1111111 && rx_b == 7'b0100001 &&
             rx_c == 7'b0111111 && rx_d == 7'b1100001) 
            sync <= 1'b1;
      end
   end      

   // Creating expected receiving data for comparison
   always @(posedge RCLK_in)
   begin
      if (sync == 1'b0) begin
         cmp_a <= 7'b0000000;
         cmp_b <= 7'b0100000;
         cmp_c <= 7'b1000000;
         cmp_d <= 7'b1100000;
      end else begin
         cmp_a <= cmp_a + 1;
         cmp_b <= cmp_b - 1;
         cmp_c <= cmp_c + 1;
         cmp_d <= cmp_d - 1;
      end
   end

   // Comparing received data with expected data,
   // Increasing error count if they are not equal
   always @(posedge RCLK_in)
   begin
      if (sync == 1'b0) begin 
         err_a <= 7'b0000000;
         err_b <= 7'b0000000;
         err_c <= 7'b0000000;
         err_d <= 7'b0000000;
         erra <= 1'b0;
         errb <= 1'b0;
         errc <= 1'b0;
         errd <= 1'b0;                           
      end else begin
        if(blink_time) begin
             erra <= 1'b0;
             errb <= 1'b0;
             errc <= 1'b0;
             errd <= 1'b0;   
        end
        if (cmp_a !== rx_a)  begin err_a <= err_a + 1; erra <= 1'b1; end 
        if (cmp_b !== rx_b)  begin err_b <= err_b + 1; errb <= 1'b1; end
        if (cmp_c !== rx_c)  begin err_c <= err_c + 1; errc <= 1'b1; end
        if (cmp_d !== rx_d)  begin err_d <= err_d + 1; errd <= 1'b1; end
      end
   end
 
   // Creating time clock for visible blink
   always @(posedge RST or posedge RCLK_in)
   begin
      if (RST) begin
         blink_count <= 0;
         blink_time <= 0;
      end else begin
`ifdef _VCP  // used to detect Aldec Verilog simulation and reduce simulation time
         if (blink_count == (2**BBITS -1)) begin       //  simulation speed-up
`else
         if (blink_count == 62500000) begin       //  ~25Mhz clock
//         if (blink_count == 250000000) begin       // ~100Mhz clock
`endif
            blink_count <= 0;
            blink_time <= 1;
         end else begin
            blink_count <= blink_count + 1;
            blink_time <= 0;
         end
      end
   end

    //  Create blinking error detects
    assign berr_a = erra && blink_count[BBITS-1]; 
    assign berr_b = errb && blink_count[BBITS-1]; 
    assign berr_c = errc && blink_count[BBITS-1]; 
    assign berr_d = errd && blink_count[BBITS-1]; 
 
 
   // Connecting signals out for status checking,
   
   always @(*)
   begin
        case (SWDIP[2:0])
            3'b000 : LED <= {~dphase};
            3'b001 : LED <= {~erra, ~errb, ~errc, ~errd};
            3'b010 : LED <= {~txpll_lock, ~rxpll_lock, ~dphase_lock, ~sync};
            3'b011 : LED <= {blink_count[BBITS-1], ~blink_count[BBITS-1], blink_count[BBITS-1], ~blink_count[BBITS-1]};
            3'b100 : LED <= {tx_a[6:5], rx_a[6:5]};
            3'b101 : LED <= {tx_b[6:5], rx_b[6:5]};
            3'b110 : LED <= {tx_c[6:5], rx_c[6:5]};
            3'b111 : LED <= {tx_d[6:5], rx_d[6:5]};
            default : LED <= {~berr_a, ~berr_b, ~berr_c, ~berr_d};
        endcase
   end
   

endmodule

      
